// ****************************************************************
// >> File Name: /home/diabio/project/al_cache/al_cache/arc_cache/arc_cache.h
// >> Author: diabiolin
// >> Created Time: Fri 25 Apr 2025 05:32:42 PM CST
// >> Description: arc algorithm
// ****************************************************************

#include "../cache_policy.h"
#include "arc_lfu_part.h"
#include "arc_lru_part.h"
#include <memory>

namespace al_cache{

template <typename Key, typename Value>
class ArcCache : public CachePolicy<Key, Value> {

public:
	explicit ArcCache(size_t capacity = 10, size_t transformThrehold = 2)
		: capacity_(capacity)
		, transformThrehold_(transformThrehold)
		, lruPart_(std::make_unique<ArcLruPart<Key, Value>>(capacity, transformThrehold))
		, lfuPart_(std::make_unique<ArcLfuPart<Key, Value>>(capacity, transformThrehold)) 
		{}

	void put(Key key, Value value) override {
		std::lock_guard<std::mutex> lock(mutex_);
		bool inGhost = checkGhostCaches(key);

		if(!inGhost){
			if(lruPart_->put(key, value)){
				lfuPart_->put(key, value);
			}
		}
		else{
			lruPart_->put(key, value);
		}
	}

	bool get(Key key, Value& value) override {
		std::lock_guard<std::mutex> lock(mutex_);
		checkGhostCaches(key);

		bool shouldTransform = false;
		if(lruPart_->get(key, value, shouldTransform)){
			if(shouldTransform){
				lfuPart_->put(key, value);
			}
			return true;
		}
		return lfuPart_->get(key, value);
	}

	Value get(Key key) override {
		Value value{};
		get(key, value);
		return value;
	}


private:
	size_t capacity_;
	size_t transformThrehold_;
	std::unique_ptr<ArcLfuPart<Key, Value>> lfuPart_;
	std::unique_ptr<ArcLruPart<Key, Value>> lruPart_;
	std::mutex mutex_;

	bool checkGhostCaches(Key key){
		bool inGhost = false;
		if(lruPart_->checkGhost(key)){
			if(lfuPart_->decreaseCapacity()){
				lruPart_->increaseCapacity();
			}
			inGhost = true;
		}
		else if(lfuPart_->checkGhost(key)){
			if(lruPart_->decreaseCapacity()){
				lfuPart_->increaseCapacity();
			}
			inGhost = true;
		}
		return inGhost;
	}
};

} // namespace al_cache
